package com.example.demoshiro.common.shiro;

import jakarta.servlet.http.HttpServletRequest;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.mgt.eis.CachingSessionDAO;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.stereotype.Component;
import org.springframework.util.DigestUtils;

import java.io.Serializable;
import java.util.concurrent.TimeUnit;

@Component
public class CustomSessionDao extends CachingSessionDAO {

    private HttpServletRequest request;

    public CustomSessionDao(HttpServletRequest request) {
        this.request = request;
    }

    private RedisTemplate getRedisTemplate() {
        // 从工厂中取出RedisTemplate实例
        RedisTemplate redisTemplate = ApplicationContextUtils.getBean("redisTemplate");
        // 将Key的序列化规则设置为字符串
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        // 将Hash中field的序列化规则设置为字符串
        redisTemplate.setHashKeySerializer(new GenericJackson2JsonRedisSerializer());

        return redisTemplate;
    }

    @Override
    protected void doUpdate(Session session) {
        if (session == null || session.getId() == null) {
            return;
        }
        saveSession(session);
    }

    @Override
    protected void doDelete(Session session) {

    }

    @Override
    protected Serializable doCreate(Session session) {
        Serializable sessionId = generateSessionId(session);
        assignSessionId(session, sessionId);
        saveSession(session);
        return sessionId;
    }

    @Override
    protected Session doReadSession(Serializable sessionId) {
        Object res = getRedisTemplate().opsForValue().get(sessionId);
        if (res == null) {
            return null;
        }
        return (Session) res;
    }

    private void saveSession(Session session) {
        String addr = request.getRemoteAddr();
        String userAgent = request.getHeader("User-Agent");
        String uId = DigestUtils.md5DigestAsHex((addr + userAgent).getBytes());
        Object resUId = getRedisTemplate().opsForValue().get(uId);
        if (resUId != null) {
            getRedisTemplate().delete(resUId);
            getRedisTemplate().delete(uId);
        }
        getRedisTemplate().opsForValue().set(uId, session.getId(), 7, TimeUnit.DAYS);
        getRedisTemplate().opsForValue().set(session.getId(), session, 7, TimeUnit.DAYS);
    }
}
